/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.mlu.jdbc.simple.codegeneration;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.SQLException;
import java.util.List;
import javax.sql.DataSource;
import org.mlu.jdbc.simple.utils.JdbcUtils;
import org.mlu.jdbc.simple.utils.ReflectionUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 *
 * @author Mlungisi Sincuba
 * @since 1.0
 */
public class DaoImplClassGenerator {

    private DataSource dataSource;
    private static final Logger logger = LoggerFactory.getLogger(DaoImplClassGenerator.class);
    private final static String METHOD_BODY_SPACE = "      ";
    private final static String MEMBER_SPACE = "   ";
    private final static String SQL_INSERT = "INSERT INTO ";

    public DaoImplClassGenerator(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    /**
     * @return the dataSource
     */
    public DataSource getDataSource() {
        return dataSource;
    }

    /**
     * @param dataSource the dataSource to set
     */
    public void setDataSource(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    public void generateGenericDaoInterfaceImpl(String src, String packageName, boolean mavenProject, String[] tableNames) throws SQLException, IOException, ClassNotFoundException {
        src = CodeUtil.getSrcPath(src, mavenProject);
        String domainPackage = packageName + ".domain.";
        packageName += ".dao.impl";
        String packagePath = CodeUtil.getPackagePath(src, packageName);

        //Loop through all columnNames
        String[] tableNamesArray = tableNames;
        tableNamesArray = CodeUtil.toTablesArray(tableNames, tableNamesArray, getDataSource());
        for (String tableName : tableNamesArray) {
            logger.debug("TableName is {}", tableName);
            StringBuilder sb = new StringBuilder("package ").append(packageName).append(";\n\n");
            //Imports
            sb.append("import ").append(packageName).append(".GenericDao;\n")
                    .append("import org.mlu.jdbc.simple.SimpleJdbc;\n")
                    .append("import org.mlu.jdbc.simple.utils.JdbcUtils;\n")
                    .append("import java.io.Serializable;\n")
                    .append("import java.util.List;\n")
                    .append("import javax.sql.DataSource;\n")
                    .append("import org.slf4j.Logger;\n")
                    .append("import org.slf4j.LoggerFactory;\n\n");

            //Class declaration
            sb.append("public class GenericDaoImpl<T> extends SimpleJdbc implements GenericDao<T> {\n\n").append(MEMBER_SPACE);

            //Fields
            sb.append("protected static Logger logger = LoggerFactory.getLogger(GenericDaoImpl.class);\n").append(MEMBER_SPACE);
            sb.append("private final static String SQL_INSERT = \"INSERT INTO \";\n\n").append(MEMBER_SPACE);

            //Contructors
            sb.append("public GenericDaoImpl() {\n      }\n\n   ")
                    .append("public GenericDaoImpl(DataSource dataSource) {\n      ")
                    .append("super(dataSource);\n   }\n\n   ")
                    .append("public GenericDaoImpl(String fileName) {\n      ")
                    .append("super(fileName);\n   }\n\n   ");

            //add method
            sb.append("public int addNew(T t) {\n").append(METHOD_BODY_SPACE)
                    .append("String className = t.getClass().getSimpleName();\n").append(METHOD_BODY_SPACE)
                    .append("String tableName = JdbcUtils.convertPropertyNameToUnderscoreName(className);\n").append(METHOD_BODY_SPACE)
                    .append("logger.debug(\"className is {}\", className);\n").append(METHOD_BODY_SPACE)
                    .append("logger.debug(\"tableName is {}\", tableName);\n").append(METHOD_BODY_SPACE)
                    .append("StringBuilder sb = new StringBuilder(SQL_INSERT).append(tableName);\n").append(METHOD_BODY_SPACE);
            String className = JdbcUtils.convertTableNameToClassName(tableName);
            String fullClassName = domainPackage + className;
            logger.debug("Full class name = {}", fullClassName);
            Class<?> classInstance = Class.forName(fullClassName);
            List<Method> declaredMethods = ReflectionUtil.getDeclaredMethods(classInstance, false);
            StringBuilder sbMethod = new StringBuilder("Object []params = {");
            for (Method method : declaredMethods) {
                 String name = method.getName();
                 if (name.startsWith("get") || name.startsWith("is")) {
                     sbMethod.append("t.").append(name).append(", ");
                 }
            }
            sbMethod.replace(sbMethod.lastIndexOf(", "), sbMethod.length(), "}");
            //            String interfaceName = CodeUtil.interfaceDeclaration(tableName, sb);
            //            CodeUtil.saveTofile(packagePath, interfaceName, sb);
        }
//        sb.append("String pk = CodeUtil.getPrimaryKey(tableNames, dataSource);\n").append(METHOD_BODY_SPACE);


//        logger.debug("generateGenericDaoInterface = \n{}", sb);
        //CodeUtil.saveTofile(packagePath, "GenericDao", sb);

    }

    public void generateDaoInterface(String src, String packageName, boolean mavenProject, String[] tableNames) throws SQLException, IOException {
        src = CodeUtil.getSrcPath(src, mavenProject);
        String basePackage = packageName;
        packageName += ".dao";
        String packagePath = CodeUtil.getPackagePath(src, packageName);

        String[] tableNamesArray = tableNames;
        tableNamesArray = CodeUtil.toTablesArray(tableNames, tableNamesArray, getDataSource());
        for (String tableName : tableNamesArray) {
            logger.debug("TableName is {}", tableName);

            StringBuilder sb = new StringBuilder("package ").append(packageName).append(";\n\n");
            String className = JdbcUtils.convertTableNameToClassName(tableName);
            sb.append("import ").append(basePackage).append(".domain.").append(className).append(";\n\n");
            String interfaceName = CodeUtil.interfaceDeclaration(tableName, sb);
            CodeUtil.saveTofile(packagePath, interfaceName, sb);
        }
    }

    public static void main(String... args) throws SQLException, IOException, ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, IllegalArgumentException, InvocationTargetException {
//        List<Method> declaredMethods = ReflectionUtil.getDeclaredMethods(Person.class, false);
//        
//        Person person = (Person) ReflectionUtil.newInstance("com.movirtu.domain.Person");
//        person.setIdNumber("12345");
//        person.setName("Tester");
//        person.setSurname("Manager");
//        StringBuilder sb = new StringBuilder("Object []params = {");
//        for (Method method : declaredMethods) {
//            String name = method.getName();
//            System.out.println("name = " + name);
//            if (name.startsWith("get")) {
//                Object returned = ReflectionUtil.invokeMethod(person, name);
//                sb.append("t.").append(name).append(", ");
//                System.out.println("returned: " + returned);
//            }
//        }
//        sb.replace(sb.lastIndexOf(", "), sb.length(), "}");
//        System.out.println("objArray = " + sb);
////        SimpleJdbc jdbc = new SimpleJdbc();
//        DaoImplClassGenerator implClassGenerator = new DaoImplClassGenerator(null);
//        implClassGenerator.generateGenericDaoInterfaceImpl(null, "com.movirtu", true, null);
////        DomainClassGenerator domainClassGenerator = new DomainClassGenerator(jdbc.getDataSource());
////        domainClassGenerator.generateDomain(null, "com.movirtu", true, null);
////        DaoClassGenerator classGenerator = new DaoClassGenerator(jdbc.getDataSource());
////        classGenerator.generateGenericDaoInterface(null, "com.movirtu", true, null);
////        classGenerator.generateDaoInterface(null, "com.movirtu", true, null);
    }
}
